import re,subprocess
import logging
# 执行svn命令
def exe_svn_command(command)->str:
    try:
        p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        stdout, stderr = p.communicate()
        stdout = stdout.decode("gbk")
        stderr = stderr.decode("gbk")
        if stderr != "":
            print("stderr:\n",stderr)
            logging.warning(stderr)
        return stdout   
    except subprocess.CalledProcessError as e:
        print(f'Subprocess failed with return code {e.returncode}')
    except FileNotFoundError:
        print('Command not found')
# 获取本地文件夹对应的 svnURl 
def get_svn_url_by_path(work_path)->str:
    match = re.search(r'URL: (svn://[^\n]*)', exe_svn_command(f"svn info \"{work_path}\""))
    if not match:
        print(f'未识别到svn_url:请确保{work_path}是svn的工作副本!')
        return ''
    return match.group(1)
# 获取本地文件夹对应的 version
def get_svn_version_by_path(work_path)->str:
    match = re.search(r'Revision:\s*([0-9|\.]+)', exe_svn_command(f"svn info \"{work_path}\""))
    if not match:
        print(f'未识别到version:请确保{work_path}是svn的工作副本!')
        return ''
    return match.group(1)
# revert 撤销所有未提交的本地修改
def revert_and_cleanup(work_path)->None:
    exe_svn_command(f"svn revert -R \"{work_path}\" && svn cleanup \"{work_path}\"")
# update 将工作副本更新到最新版本
def update(work_path)->None:
    exe_svn_command(f"svn update \"{work_path}\"")
# 获取文件的guid
def get_guid(filepath)->str:
    text = ''
    with open(filepath, mode='r') as file:
        text = file.read()
    match = re.search(r'guid:\s*(\w+)', text)
    if not match:
        print(f'.meta 文件：{filepath} 解析 GUID 失败')
        return ''
    return match.group(1)
# 迭代更新，直到最新版本
def iterate_to_up_to_date(work_path,version,mate_dict)->dict:
    diff_mate_list=check_version(work_path,version)
    if not len(diff_mate_list):
        return mate_dict
    version=get_svn_url_by_path(work_path)
    for diff_mate in diff_mate_list:  
        status = diff_mate['status']  
        path = diff_mate['path']  
        if status == 'D' and path in mate_dict:  
            del mate_dict[path]  
        else: 
            mate_dict[path] = get_guid(f"{work_path}\\{path}")  
    return iterate_to_up_to_date(work_path,version,mate_dict)
# 获取工作副本的mate文件信息
def get_project_mates(work_path):
    mate_dict = {}
    svn_assets_url = get_svn_url_by_path(work_path)
    if svn_assets_url !='':
        revert_and_cleanup(work_path)
        update(work_path)
        version=get_svn_version_by_path(work_path)
        metafile_list = exe_svn_command(f"svn list -R {svn_assets_url} --non-interactive | find \".meta\" ").splitlines()
        for file in metafile_list:
            if "~/" in file:
                continue
            mate_dict[file]=get_guid(f"{work_path}\\{file}")
        iterate_to_up_to_date(work_path,version,mate_dict)
    return mate_dict
# 检查当前工作副本与新版本的差异
def check_version(work_path,version):
    diff_list=[]
    text = exe_svn_command(f"cd {work_path} && svn update")
    match=re.search(r'revision[\s]*([^\n]*)\.',text)
    if not match:
        print(f'检查失败:请确保{work_path}是svn的工作副本!')
    elif match.group(1)==version:
        print(f"当前已是最新版本！")
    else:
        for line in text.splitlines():
            match=re.search(r'([A-Z])[\s]*([^\n]*.meta)',line)
            if not match or "~/" in match.group(2):
                continue
            diff_list.append({"status":match.group(1),"path":match.group(2)})
    return diff_list
# 示例
if __name__ == '__main__':
    work_path=r"D:\work\svn\SvnToolTest"
    mate_dict=get_project_mates(work_path)